package cn.learn.office.excel_v2;


import cn.learn.office.excel_v2.sort.HandlerColumnSort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * Excel排序类型的对象工厂；
 * 更改：删除了注解，不根据注解去获取类；现在根据指定包，并实现了接口的
 *
 * @author huangyezhan
 * @version 2.0
 * @date 2019年02月23日16:16
 */
@Deprecated
public class ExcelSortFactory {
    private static final Logger logger = LoggerFactory.getLogger(ExcelSortFactory.class);

    private ExcelSortFactory() {
        init();
    }

    /**
     * 静态内部类，单例模式
     * 只有第一次调用后才会创建对象，延迟初始化，线程安全
     */
    private static class ExcelSortFactoryInstance {
        private static final ExcelSortFactory instance = new ExcelSortFactory();
    }

    public static ExcelSortFactory getInstance() {
        return ExcelSortFactory.ExcelSortFactoryInstance.instance;
    }


    /**
     * 两种不同的文件的文件前缀，如：
     * jar:file:/C:/Users
     * file：/C:/Users
     */
    private static final String                   JAR                = "jar";
    private static final String                   FILE               = "file";
    /**
     * .class格式的文件
     */
    private static final String                   CLASS_FILE         = ".class";
    /**
     * 指定包名
     */
    private static final String                   EXCEL_SORT_PACKAGE = ExcelSortFactory.class.getPackage().getName() + ".sort";
    /**
     * 所有的规则都要实现统一接口
     */
    private static final Class<HandlerColumnSort> EXCEL_SORT         = HandlerColumnSort.class;
    /**
     * 放置所有排序方法的实例
     */
    private List<HandlerColumnSort> excelSortList;

    private final ClassLoader classLoader = getClass().getClassLoader();


    /**
     * 根据传进来的注解名称返回对象
     *
     * @param className 注解所在的类
     * @return 返回该注解的对象
     */
    public HandlerColumnSort createExcelSort(Class<? extends HandlerColumnSort> className) {
        try {
            for (HandlerColumnSort clz : excelSortList) {
                if (className.isAssignableFrom(clz.getClass())) {
                    return clz;
                }
            }
        } catch (Exception e) {
            logger.info("获取Excel排序对象失败：{}", e.getMessage());
        }
        return null;
    }

    /**
     * 根据不同的包格式去加载类
     * 加载指定路径下所有类，并把生成的对象存起来
     */
    private void init() {
        excelSortList = new ArrayList<>();
        try {
            Enumeration<URL> urlEnumeration = classLoader.getResources(EXCEL_SORT_PACKAGE.replace(".", "/"));
            while (urlEnumeration.hasMoreElements()) {
                URL    url      = urlEnumeration.nextElement();
                String protocol = url.getProtocol();
                logger.info("该文件类型：" + protocol);
                switch (protocol) {
                    case JAR:
                        scanJar(url);
                        break;
                    case FILE:
                        scanFile(url.toURI());
                        break;
                    default:
                        logger.info("不支持该文件类型：" + protocol);
                }
            }
        } catch (Exception e) {
            logger.info(e.getMessage());
        }
    }

    /**
     * 扫描JAR文件
     *
     * @param url 类文件的路径
     * @throws IOException io异常
     */
    private void scanJar(URL url) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        JarURLConnection connection = (JarURLConnection) url.openConnection();
        if (connection != null) {
            JarFile jarFile = connection.getJarFile();
            if (jarFile != null) {
                //得到改jar文件下的类实体
                Enumeration<JarEntry> entries = jarFile.entries();
                while (entries.hasMoreElements()) {
                    JarEntry jarEntry     = entries.nextElement();
                    String   jarEntryName = jarEntry.getName();

                    //这里我们需要过滤：不是class文件和不在EXCEL_SORT_PACKAGE包名下的类
                    if (jarEntryName.endsWith(CLASS_FILE) && jarEntryName.replace("/", ".").startsWith(EXCEL_SORT_PACKAGE)) {
                        String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", ".");
                        //Class<?> clz       = Class.forName(className);
                        this.setExcelSortInstances(className);
                    }
                }
            }
        }
    }

    /**
     * 扫描文件下的类
     *
     * @param uri 指定文件的uri
     */
    private void scanFile(URI uri) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        File   f     = new File(uri);
        File[] files = f.listFiles();
        if (files != null) {
            for (int i = 0; i < files.length; ++i) {
                File file = files[i];
                if (file.getName().endsWith(CLASS_FILE)) {
                    String className = EXCEL_SORT_PACKAGE + "." + file.getName().replace(CLASS_FILE, "");
                    this.setExcelSortInstances(className);
                }
            }
        }
    }

    /**
     * 把所有的类生成单例的对象
     *
     * @param className 类的全限定名称
     * @throws ClassNotFoundException 类异常
     * @throws IllegalAccessException 权限修饰异常不是public修饰的
     * @throws InstantiationException 实例异常
     */
    private void setExcelSortInstances(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class<?> clz = classLoader.loadClass(className);
        //判断是不是某接口的实现类（继承类）
        if (EXCEL_SORT.isAssignableFrom(clz) && clz != EXCEL_SORT) {
            excelSortList.add((HandlerColumnSort) clz.newInstance());
        }
    }

}
